<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 14-4-25
 * Time: 下午1:52
 */

namespace Common\Org\Util;

/**
 * Class InputData
 * @package Common\Org\Util
 * 输入数据的处理类(验证)
 */
class InputData{
    private $errorArr=array();//错误信息数组
    private $error;//单个错误信息
    private $bool;//状态，true或false
    private $status=0;//返回客户端状态标志,默认为0

    public static $nick_reg = '/^[a-zA-Z0-9\x{4e00}-\x{9fa5}·]+$/u';//真实姓名正则表达式
    public static $pass_reg = '/^[\x21-\x7E]{6,12}$/';//密码正则表达式
    public static $int_reg = '/^[0-9]+$/';//整数正则表达式
    public static $email_reg='/^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/';//邮箱正则表达式
    public static $mobile_reg='/^(13[0-9]|145|147|15[0-9]|170|177|18[0-9])[0-9]{8}$/';//手机正则表达式
    //public static $tel_reg = '/^((00852\-)|((0[1-9][0-9]{1,2})\-)){0,1}([2-9][0-9]{6,7}){1}(\-[0-9]{1,4}){0,1}$/';//固话正则表达式
    public static $tel_reg = '/^((00852\-)|((0[1-9][0-9]{1,2})(\-){0,1})){0,1}([2-9][0-9]{6,7}){1}(\-[0-9]{1,4}){0,1}$/';//固话正则表达式
    //public static $fax_reg = '/^((00852\-)|((0[1-9][0-9]{1,2})\-)){0,1}([2-9][0-9]{6,7}){1}(\-[0-9]{1,4}){0,1}$/';//传真正则表达式
    public static $fax_reg = '/^((00852\-)|((0[1-9][0-9]{1,2})(\-){0,1})){0,1}([2-9][0-9]{6,7}){1}(\-[0-9]{1,4}){0,1}$/';//传真正则表达式
//    private static $website_reg = '/^([\w-]+\.)+[\w-]+([\w-.\/?%&=]*)?$/';//网址正则表达式
    public static $website_reg = '/^([\w-]+\.)+[\w-]+(:[0-9]+)?([\w-.\/?%&=]*)?$/';//网址正则表达式
    public static $http_website_reg = '/^(http(s)?:\/\/)?([\w-]+\.)+[\w-]+(:[0-9]+)?([\w-.\/?%&=]*)?$/';//网址正则表达式
    public static $idCardNumber_reg = '/(^\d{17}([0-9]|[Xx])$)/';//身份证号码正则表达式

    private $data=array();//要验证的字段及验证规则数组
    private $single = true;//是返回单个错误信息，还是返回错误信息数组，如果为true，返回单个错误信息，否则返回错误信息数组

    /**
     * @param array $data 要验证的字段及验证规则数组
     * @return $this
     *
     * $data结构
     * $data=array(
     *      'field'=>$field,
     *      'method'=>$method,
     *      'tip'=>$errorTip,
     *      'condition'=>array(
     *          //自定义，如下
     *          'status'=>0
     *          'length1'=>$length1,
     *          'length2'=>$length2,
     *          'regex'=>$regex,
     *          'opt'=>$opt,
     *          .....
     *      )
     * )
     *
     * 设置要验证的字段及验证规则
     */
    public function data($data=array()){
        $this->data = $data;
        return $this;
    }

    /**
     * @param bool $bool 是否要设置结果的返回是单个返回，还是批量返回数组
     * @return $this
     */
    public function single($bool=true){
        $this->single = $bool;
        return $this;
    }

    /**
     * 获取返回信息
     */
    private function getResult(){
        if($this->single){
            return array('error'=>$this->error,'status'=>$this->status);
        } else {
            return $this->errorArr;
        }
    }

    /**
     * @param $field 要验证的数据
     * @param $method 方法代称
     * @param string $errorTip 错误提示
     * @param array $condition 扩展数据
     */
    private function callVerifyMethod($field,$method,$errorTip='',$condition=array()){
        switch($method){
            //长度验证
            case 'length':
                $this->checkLength($condition['opt'],$field,$condition['length_type'],$errorTip,$condition['length1'],$condition['length2'],$condition['status']);
                break;

            //密码格式
            case 'password':
                $this->checkPassword($field,$errorTip,$condition['status']);
                break;

            //邮件格式
            case 'email':
                $this->checkEmail($field,$errorTip,$condition['status']);
                break;

            //手机格式
            case 'mobile':
                $this->checkMobile($field,$errorTip,$condition['status']);
                break;

            //固话格式
            case 'tel':
                $this->checkTel($field,$errorTip,$condition['status']);
                break;

            //传真格式
            case 'fax':
                $this->checkFax($field,$errorTip,$condition['status']);
                break;

            //网址格式
            case 'website':
                $this->checkWebsite($field,$errorTip,$condition['status']);
                break;

            //使用正则表达式验证
            case 'regex':
                $this->checkByRegex($field,$condition['regex'],$errorTip,$condition['status']);
                break;

            //验证不能为空
            case 'require':
                $this->checkEmpty($field,$errorTip,$condition['status']);
                break;

            //验证是否为整数
            case 'int':
                $this->checkInt($field,$errorTip,$condition['status']);
                break;

            //是否为数字
            case 'num':
                $this->checkNum($field,$errorTip,$condition['status']);
                break;

            //是否为浮点数
            case 'float':
                $this->checkFloat($field,$errorTip,$condition['status']);
                break;

            //真实姓名格式验证
            case 'nickname':
                $this->checkNickname($field,$errorTip,$condition['status']);
                break;

            //验证两字符串是否相等
            case 'equal':
                $this->checkEqual($field,$condition['str'],$condition['equal_type'],$errorTip,$condition['status']);
                break;

            //验证是否符合日期格式
            case 'date':
                $this->checkDate($field,$condition['delimeter'],$errorTip,$condition['status']);
                break;

            //验证身份证号码格式
            case 'idCard':
                $this->checkIDCardNumber($field,$errorTip,$condition['status']);
                break;
        }
    }

    /**
     * 批量处理
     */
    private function checkMulti(){
        foreach($this->data as $val){
            //调用不同的验证方法
            if(strpos($val['method'],':')!==false){
                $methodArr = explode(':',$val['method']);
                $tipArr = explode(':',$val['tip']);

                foreach($methodArr as $mkey=>$mval){
                    $this->callVerifyMethod($val['field'],$mval,$tipArr[$mkey],$val['condition']);

                    //如果是单个返回，而且有错误发生，直接返回
                    if($this->single && !$this->bool){
                        break;
                    }
                }
            } else {
                $this->callVerifyMethod($val['field'],$val['method'],$val['tip'],$val['condition']);
            }

            //如果是单个返回，而且有错误发生，直接返回
            if($this->single && !$this->bool){
                break;
            }
        }
    }

    /**
     * 验证方法，通过此方法调用相应的验证方法
     */
    public function check(){
        $args_num = func_num_args();
        if($args_num>1 && $args_num<5){
            $args = func_get_args();

            $field = array_shift($args);
            $method = array_shift($args);

            $errorTip = array_shift($args);

            $condition = array_shift($args);

            $this->single = true;
            $this->callVerifyMethod($field,$method,$errorTip,$condition);
        } else {
            $this->checkMulti();
        }

        return $this->getResult();
    }

    /**
     * @param $errorTip 错误提示
     * @param int $status 返回客户端的状态标识
     * 设置错误提示，用于返回
     */
    private function setErrorTip($errorTip,$status=0){
        if($this->single){
            $this->error=$errorTip;
            $this->status = isEmpty($status)?0:$status;
        } else {
            $this->errorArr[] = $errorTip;
        }
    }

    /**
     * @param $field 验证字符串
     * @param string $errorTip 错误提示，默认为空
     * @param int $status 返回客户端的状态标识符
     * 验证字符串是否为空
     */
    private function checkEmpty($field,$errorTip='',$status=0){
        if(isEmpty($field)){
            $errorTip = isEmpty($errorTip)? '不能为空':$errorTip;
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        } else {
            $this->bool = true;
        }

        return $this->bool;
    }

    /**
     * @param $str 字符串
     * 获取字符串长度，含中文
     */
    private function getStrLength($str){
        if(isEmpty($str)){
            return 0;
        }
        if(function_exists('mb_strlen')){
            return ceil((strlen($str) + mb_strlen($str, 'UTF8')) / 4);
        } else {
            mb_regex_encoding('utf-8');
            $str = mb_ereg_replace('[\xa0-\xff]','aa',$str);//替换中文（双字节字符）为2个字符（单字节字符）
            return ceil(strlen($str)/2);
        }
    }

    /**
     * @param $str 要验证的字符串
     * @param $astr 要比较的字符串
     * @param $type 是否区分大小写 $type=1区分大小写，$type=2 不区分大小写
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识符
     * 验证两字符串是否相等
     */
    private function checkEqual($str,$astr,$type=1,$errorTip='',$status=0){
        if(isEmpty($str) || isEmpty($astr)) return;

        if(intval($type)==2){
            $str = strtolower($str);
            $astr = strtolower($astr);
        }

        if($str == $astr){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'不相等';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }

    /**
     * @param $str 要验证的字符串
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识符
     * 验证是否为数字
     */
    private function checkNum($str,$errorTip='',$status=0){
        if(isEmpty($str)) return;
        if(is_numeric($str)){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'必须为数字';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }

    /**
     * @param $str 要验证的字符串
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识符
     * @return bool
     * 验证是否为浮点数
     */
    private function checkFloat($str,$errorTip='',$status=0){
        if(isEmpty($str)) return;
        if(is_float($str)){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'必须为浮点数';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }

    /**
     * @param $str 要验证的字符串
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识符
     * @return bool
     * 验证是否为整数
     */
    private function checkInt($str,$errorTip='',$status=0){
        if(isEmpty($str)) return;
        if(preg_match(self::$int_reg,$str)){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'必须为整数';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }

    /**
     * @param $nickname 真实姓名
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识符
     * @return bool
     * 验证真实姓名的格式
     */
    private function checkNickname($nickname,$errorTip='',$status=0){
        if(isEmpty($nickname)) return;
        if(preg_match(self::$nick_reg,$nickname)){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'真实姓名格式错误';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }

    /**
     * @param $password 要验证的字符串，即密码
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识符
     * 验证密码格式
     */
    private function checkPassword($password,$errorTip='',$status=0){
        if(isEmpty($password)) return;
        if(preg_match(self::$pass_reg,$password)){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'密码格式不正确';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }

    /**
     * @param string $opt 比较操作类型，可有‘gt’,'egt','lt'等
     * @param $str 比较的字符串
     * @param $type 标志 $type=1 2个英文字符算一个字，$type=2 1个英文字符算一个字
     * @param string $errorTip 错误提示
     * @param int $length1 限制长度1，不能为空
     * @param int $length2 限制长度2，可为空
     * @param int $status 返回客户端的状态标识
     * @return array
     * 验证字符串长度
     */
    private function checkLength($opt='gt',$str,$type=1,$errorTip='',$length1=10,$length2=0,$status=0){
        if(isEmpty($str)) return;
        if(intval($type)==2){
            $str_length = strlen($str);
        } else {
            if(function_exists('abslength')){
                $str_length = abslength($str);//获取长度
            } else {
                $str_length = $this->getStrLength($str);
            }
        }

        //比较操作
        switch($opt){
            //大于（〉）
            case 'gt':
                if($str_length>$length1){
                    $this->bool = true;
                } else {
                    $errorTip = $errorTip?$errorTip:'不能超过'.$length1.'个字符';
                    $this->setErrorTip($errorTip,$status);
//                    $this->error[] = $errorTip?$errorTip:'不能超过'.$length1.'个字符';
                    $this->bool = false;
                }
                break;

            //小于（<）
            case 'lt':
                if($str_length<$length1){
                    $this->bool = true;
                } else {
                    $errorTip = $errorTip?$errorTip:'不能少于'.$length1.'个字符';
                    $this->setErrorTip($errorTip,$status);
                    $this->bool = false;
                }
                break;

            //大于等于>=
            case 'egt':
                if($str_length>=$length1){
                    $this->bool = true;
                } else {
                    $errorTip = $errorTip?$errorTip:'必须在'.$length1.'个字符以内';
                    $this->setErrorTip($errorTip,$status);
                    $this->bool = false;
                }
                break;

            //小于等于<=
            case 'elt':
                if($str_length<=$length1){
                    $this->bool = true;
                } else {
                    $errorTip = $errorTip?$errorTip:'必须超过'.$length1.'个字符';
                    $this->setErrorTip($errorTip,$status);
                    $this->bool = false;
                }
                break;

            //等于==
            case 'eq':
                if($str_length==$length1){
                    $this->bool = true;
                } else {
                    $errorTip = $errorTip?$errorTip:'不能为'.$length1.'个字符';
                    $this->setErrorTip($errorTip,$status);
                    $this->bool = false;
                }
                break;

            //不等于!=
            case 'neq':
                if($str_length!=$length1){
                    $this->bool = true;
                } else {
                    $errorTip = $errorTip?$errorTip:'必须为'.$length1.'个字符';
                    $this->setErrorTip($errorTip,$status);
                    $this->bool = false;
                }
                break;

            //在某个范围
            case 'between':
                if($str_length>=$length1 && $str_length<=$length2){
                    $this->bool = true;
                } else {
                    $errorTip = $errorTip?$errorTip:'不能在'.$length1.'个到'.$length2.'个字符以内';
                    $this->setErrorTip($errorTip,$status);
                    $this->bool = false;
                }
                break;

            //不在某个范围
            case 'not between':
                if($str_length<$length1 || $str_length>$length2){
                    $this->bool = true;
                } else {
                    $errorTip = $errorTip?$errorTip:'必须在'.$length1.'个到'.$length2.'个字符以内';
                    $this->setErrorTip($errorTip,$status);
                    $this->bool = false;
                }
                break;
        }

        return $this->bool;
    }

    /**
     * @param $email 邮箱
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识
     * 邮箱验证
     */
    private function checkEmail($email,$errorTip='',$status=0){
        if(isEmpty($email)) return;
        if(preg_match(self::$email_reg,$email)){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'邮箱格式不正确';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }

    /**
     * @param $mobile 手机号
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识
     * 验证手机号格式
     */
    private function checkMobile($mobile,$errorTip='',$status=0){
        if(isEmpty($mobile)) return;
        if(preg_match(self::$mobile_reg,$mobile)){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'手机格式不正确';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }

    /**
     * @param $tel 固话号码
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识
     * 验证固话号码格式
     */
    private function checkTel($tel,$errorTip='',$status=0){
        if(isEmpty($tel)) return;
        if(preg_match(self::$tel_reg,$tel)){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'电话号码格式不正确';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }

    /**
     * @param $fax 传真号码
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识
     * 验证传真号码格式
     */
    private function checkFax($fax,$errorTip='',$status=0){
        if(isEmpty($fax)) return;
        if(preg_match(self::$fax_reg,$fax)){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'传真号码格式不正确';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }

    /**
     * @param $website 网址URL
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识
     * 验证网址格式
     */
    private function checkWebsite($website,$errorTip='',$status=0){
        if(isEmpty($website)) return;
        $website = preg_replace('/http(s){0,1}:\/\//','',$website);
        if(preg_match(self::$website_reg,$website)){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'网址格式不正确';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }

    /**
     * @param $idCardNumber 身份证号码
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识
     * @return bool
     * 验证身份证号码的格式
     */
    private function checkIDCardNumber($idCardNumber,$errorTip='',$status=0){
        if(isEmpty($idCardNumber)) return;
        if(preg_match(self::$idCardNumber_reg,$idCardNumber)){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'身份证格式不正确';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }

    /**
     * @param $date 待检测的日期字符串
     * @param string $delimeter 日期的年月日日分隔符，默认为‘-’
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识
     * @return bool
     * 验证日期格式是否正确
     * 格式如2014－06－12，2014/06/12才正确
     */
    private function checkDate($date,$delimeter='-',$errorTip='',$status=0){
        if(isEmpty($date)) return;
        if(isEmpty($delimeter)) $delimeter = '-';
        $arr = explode($delimeter,$date);
        if(count($arr)!=3){
            $errorTip = $errorTip?$errorTip:'日期格式错误';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        } else {
            if(checkdate($arr[1],$arr[2],$arr[0])){
                $this->bool = true;
            }else{
                $errorTip = $errorTip?$errorTip:'日期格式错误';
                $this->setErrorTip($errorTip,$status);
                $this->bool = false;
            }
        }
        return $this->bool;
    }

    /**
     * @param $field 字段
     * @param $regex 正则表达式
     * @param string $errorTip 错误提示
     * @param int $status 返回客户端的状态标识
     * 通过正则表达式验证
     */
    private function checkByRegex($field,$regex,$errorTip='',$status=0){
        if(isEmpty($field)) return;
        if(preg_match($regex,$field)){
            $this->bool = true;
        } else {
            $errorTip = $errorTip?$errorTip:'格式不正确';
            $this->setErrorTip($errorTip,$status);
            $this->bool = false;
        }

        return $this->bool;
    }
}